package com.study.spring.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @author lirongpeng
 * @Component 把该类加入Spring IOC 容器中
 * @Aspect 把该类声明成一个切面
 */
@Component
@Aspect
public class AopConfig {

    /**
     * 声明切入表达式
     */
    @Pointcut(value = "execution(* com.study.spring.aop.*.*(..))")
    public void declareJoinPointExpression(){}

    /**
     * 声明该方法是一个前置通知，在目标方法执行方法之前执行
     */
    @Before("declareJoinPointExpression()")
    public void before(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());


        System.out.println("--@Before--methodName:" + methodName + "--Args:" + args);
    }

    /**
     * 声明该方法是一个后置通知，在目标方法执行方法之后执行
     * 无论是否出现异常都执行
     * 在后置通知中不能访问执行方法的返回值
     */
    @After("declareJoinPointExpression()")
    public void after(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("--@After--methodName:" + methodName);
    }

    /**
     * 返回通知
     * 在方法正常结束执行的代码
     * 可以访问到方法的返回值
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "declareJoinPointExpression()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("--@AfterReturnin--methodName:" + methodName + " -- result: " + result);
    }

    /**
     * 异常通知
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(value = "declareJoinPointExpression()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("--@AfterThrowing--methodName:" + methodName + " -- Exception: " + e);
    }

    /**
     * 环绕通知，需要携带ProceedingJoinPoint 类型的参数
     * 环绕通知类似于动态代理的全过程： ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
     * 且环绕通知必须要有返回值，返回值即为目标方法的返回值
     * @param pdj
     * @return
     */
    /*@Around(value = "execution(* com.study.spring.aop.*.*(..))")
    public Object around(ProceedingJoinPoint pdj){
        String methodName = pdj.getSignature().getName();
         List<Object> args = Arrays.asList(pdj.getArgs());

        Object result = null;
        try {
            // 前置通知
            System.out.println("@Befor");
            result = pdj.proceed();
            // 返回通知
            System.out.println("@AfterReturning： "  + result);

        } catch (Throwable e) {
            e.printStackTrace();
            // 异常通知
            System.out.println("@AfterThrowing");
        }

        // 后置通知
        System.out.println("@After");

        return result;
    }*/

}
